package com.infopatent.shldevtools.util;

import com.infopatent.shldevtools.tools.GetBigFileMD5Tools;
import com.infopatent.shldevtools.tools.MySimpleZipTools;
import org.apache.log4j.LogManager;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 重新编写的文件传输工具, 更加体现工具性质, 不含业务逻辑, 适用于所有项目
 * Created by lucas on 17/2/24.
 */
public class FileTransferUtil {
    /**
     * 同步密匙, 只有持有同步密匙的程序, 才能和我们的程序通信, 否则直接断开连接
     */
    private static String syncKey = "ne145g1ey1s1588fsy431645h1252";
    private static ArrayList<File> holdFiles = new ArrayList<File>();
    private static final int BUFFER = 8192;
    private static final org.apache.log4j.Logger log = LogManager.getLogger(FileTransferUtil.class);
    private static final String FILE_TMP_PATH = "~/tmp";

    /**
     * 发送文件线程, 发送指定文件, 到指定服务器IP 的指定PORT
     * @param serverIp 指定服务器
     * @param serverPort 指定端口
     * @param fileToBeSend 发送的文件
     * @return Thread
     */
    public static Thread SendFileThread(final String serverIp, final Integer serverPort, final File fileToBeSend){
        return new Thread() {

            Socket socket;
            DataInputStream dis;
            DataOutputStream dos;
            DataInputStream fis;

            @Override
            public void run() {
                boolean continueFlag = true;
                while (continueFlag){

                    //传输文件
                    try {
                        sleep(2000);
                        socket = new Socket(serverIp, serverPort);
                        log.info("建立socket连接...");

                        dis = new DataInputStream(socket.getInputStream());

                        dos = new DataOutputStream(socket.getOutputStream());

                        fis = new DataInputStream(new FileInputStream(fileToBeSend));

                        dos.writeUTF("sendFile");

                        //发送文件名称
                        dos.writeUTF(fileToBeSend.getName());
                        log.info("发送文件名称:" + fileToBeSend.getName());
                        //发送文件大小
                        dos.writeLong(fileToBeSend.length());
                        log.info("发送文件大小:" + fileToBeSend.length());
                        //文件跳过尺寸
                        long skipSize = dis.readLong();

                        if (skipSize <= 0) {
                            log.info("文件不存在,新建文件...");
                        } else {
                            log.info("文件已存在,续传文件...");
                            fis.skip(skipSize);
                        }

                        byte[] buf = new byte[BUFFER];
                        //开始传输文件
                        log.info("文件传输开始...");
                        int read;
                        while ((read = fis.read(buf)) != -1) {
                            dos.write(buf, 0, read);
                        }
                        dos.flush();

                        log.info("文件传输完成...");

                    } catch (Exception ex) {
                        Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
                        continue;
                    } finally {
                        try {

                            dis.close();
                            dos.close();
                            fis.close();
                            socket.close();
                        } catch (Exception ex) {
                            Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
                            continue;
                        }
                    }

                    //验证文件MD5
                    String localFileMd5 = GetBigFileMD5Tools.getMD5(fileToBeSend);
                    try {
                        sleep(2000);
                        socket = new Socket(serverIp, serverPort);

                        dis = new DataInputStream(socket.getInputStream());

                        dos = new DataOutputStream(socket.getOutputStream());

                        fis = new DataInputStream(new FileInputStream(fileToBeSend));

                        dos.writeUTF("checkMd5");
                        //发送文件名称
                        dos.writeUTF(fileToBeSend.getName());

                        String distanceFileMd5 = dis.readUTF();

                        if (localFileMd5 == null ? distanceFileMd5 == null : localFileMd5.equals(distanceFileMd5)) {
                            log.info("文件:" + fileToBeSend.getName() + " MD5验证通过.. 开始解压/确认完成远程文件.");
                            dos.writeUTF("md5Right");

                            String fileSaveOrDecompressResult = dis.readUTF();

                            if ("decompressSuccess".equals(fileSaveOrDecompressResult)) {
                                log.info("文件解压完成");
                                break;
                            } else if ("saveSuccess".equals(fileSaveOrDecompressResult)) {
                                log.info("文件传输完成");
                                break;
                            }
                        } else {
                            log.info("文件:" + fileToBeSend.getName() + " MD5验证失败.. 开始删除远程文件.");
                            dos.writeUTF("md5Wrong");

                            String deleteResult = dis.readUTF();

                            if ("deleteDone".equals(deleteResult)) {
                                log.info("文件删除完成. 重新传输");
                            }
                        }

                    } catch (Exception ex) {
                        Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
                    } finally {
                        try {

                            dis.close();
                            dos.close();
                            fis.close();
                            socket.close();
                        } catch (Exception ex) {
                            Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
                            continue;
                        }
                    }

                }
            }
        };
    }

    public Thread HoldFileThread(final Integer listenPort){
        return new Thread() {

            ServerSocket serverSocket;
            Socket socket;
            DataInputStream dis;
            DataOutputStream dos;
            DataOutputStream fos;

            @Override
            public void run(){
                boolean continueFlag = true;
                while (continueFlag){

                    try {
                        sleep(2000);
                        serverSocket = new ServerSocket(listenPort);
                        socket = serverSocket.accept();
                        log.info("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort());
                        dis = new DataInputStream(socket.getInputStream());

                        dos = new DataOutputStream(socket.getOutputStream());

                        String actionFlag = dis.readUTF();

                        if ("sendFile".equals(actionFlag)) {

                            //获取文件名称
                            String fileName = dis.readUTF();
                            log.info("接收文件名称:" + fileName);
                            //获取文件大小
                            Long fileSize = dis.readLong();
                            log.info("接收文件大小:" + fileSize);

                            File receiveFile = new File(FILE_TMP_PATH, fileName);

                            if (receiveFile.getParentFile() != null) {
                                if (!receiveFile.getParentFile().exists()) {
                                    receiveFile.getParentFile().mkdirs();
                                }
                            }

                            if (receiveFile.exists()) {
                                if (receiveFile.length() > fileSize) {
                                    receiveFile.delete();
                                    dos.writeLong(0);
                                    fos = new DataOutputStream(new FileOutputStream(receiveFile));
                                } else {
                                    dos.writeLong(receiveFile.length());
                                    fos = new DataOutputStream(new FileOutputStream(receiveFile, true));
                                }
                            } else {
                                dos.writeLong(0);
                                fos = new DataOutputStream(new FileOutputStream(receiveFile));
                            }

                            //开始接收文件
                            log.info("开始接收文件...");
                            byte[] buf = new byte[BUFFER];
                            int read;
                            long passedlen = 0 + receiveFile.length();
                            while ((read = dis.read(buf)) != -1) {
                                passedlen += read;
                                fos.write(buf, 0, read);
                                log.info("文件[" + fileName + "]已经接收: " + passedlen * 100L / fileSize + "%");
                            }
                            fos.flush();
                            log.info("文件接收完成...");

                        } else if ("checkMd5".equals(actionFlag)) {
                            String receiveFileName = dis.readUTF();
                            File receiveFile = new File(FILE_TMP_PATH, receiveFileName);
                            String mD5 = GetBigFileMD5Tools.getMD5(receiveFile);
                            dos.writeUTF(mD5);

                            String md5CheckResult = dis.readUTF();

                            if ("md5Right".equals(md5CheckResult)) {
                                dos.writeUTF("saveSuccess");
                                log.info("文件接收完成!...");
//                              break;

                            } else if ("md5Wrong".equals(md5CheckResult)) {
                                receiveFile.delete();
                                dos.writeUTF("deleteDone");

                                log.info("md5验证错误文件删除完成,文件重新传输..");

                            }

                        }

                    } catch (Exception ex) {
                        Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
                    } finally {
                        try {

                            dis.close();
                            dos.close();
                            fos.close();
                            socket.close();

                        } catch (Exception ex) {
                            Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }

//                    //传输文件
//                    try {
//                        sleep(2000);
//                        socket = ssocket.accept();
//
//                        log.info("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort());
//                        log.info("建立socket连接... socket超时时间:" + socket.getSoTimeout());
//
//                        dis = new DataInputStream(socket.getInputStream());
//
//                        dos = new DataOutputStream(socket.getOutputStream());
//
//                        fis = new DataInputStream(new FileInputStream(sendFilePath));
//
//                        dos.writeUTF("sendFile");
//
//                        //发送文件名称
//                        dos.writeUTF(sendFile.getName());
//                        log.info("发送文件名称:" + sendFile.getName());
//                        //发送文件大小
//                        dos.writeLong(sendFile.length());
//                        log.info("发送文件大小:" + sendFile.length());
//                        //文件跳过尺寸
//                        long skipSize = dis.readLong();
//
//                        if (skipSize <= 0) {
//                            log.info("文件不存在,新建文件...");
//                        } else {
//                            log.info("文件已存在,续传文件...");
//                            fis.skip(skipSize);
//                        }
//
//                        byte[] buf = new byte[BUFFER];
//                        //开始传输文件
//                        log.info("文件传输开始...");
//                        int read;
//                        while ((read = fis.read(buf)) != -1) {
//                            dos.write(buf, 0, read);
//                        }
//                        dos.flush();
//
//                        log.info("文件传输完成...");
//
//                    } catch (Exception ex) {
//                        Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
//                        continue;
//                    } finally {
//                        try {
//                            dis.close();
//                            dos.close();
//                            fis.close();
//                            socket.close();
//
//                        } catch (Exception ex) {
//                            Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
//                            continue;
//                        }
//                    }
//
//                    //验证文件MD5
//                    String localFileMd5 = GetBigFileMD5Tools.getMD5(sendFile);
//                    try {
//                        sleep(2000);
//                        socket = ssocket.accept();
//                        log.info("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort());
//                        dis = new DataInputStream(socket.getInputStream());
//
//                        dos = new DataOutputStream(socket.getOutputStream());
//
//                        fis = new DataInputStream(new FileInputStream(sendFilePath));
//
//                        dos.writeUTF("checkMd5");
//                        //发送文件名称
//                        dos.writeUTF(sendFile.getName());
//
//                        String distanceFileMd5 = dis.readUTF();
//
//                        if (localFileMd5 == null ? distanceFileMd5 == null : localFileMd5.equals(distanceFileMd5)) {
//                            log.info("文件:" + sendFile.getName() + " MD5验证通过.. 开始解压/确认完成远程文件.");
//                            dos.writeUTF("md5Right");
//
//                            String fileSaveOrDecompressResult = dis.readUTF();
//
//                            if ("decompressSuccess".equals(fileSaveOrDecompressResult)) {
//                                log.info("文件解压完成");
//                                break;
//                            } else if ("saveSuccess".equals(fileSaveOrDecompressResult)) {
//                                log.info("文件传输完成");
//                                break;
//                            }
//                        } else {
//                            log.info("文件:" + sendFile.getName() + " MD5验证失败.. 开始删除远程文件.");
//                            dos.writeUTF("md5Wrong");
//
//                            String deleteResult = dis.readUTF();
//
//                            if ("deleteDone".equals(deleteResult)) {
//                                log.info("文件删除完成. 重新传输");
//                            }
//                        }
//
//                    } catch (Exception ex) {
//                        Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
//                    } finally {
//                        try {
//
//                            dis.close();
//                            dos.close();
//                            fis.close();
//                            socket.close();
//
//                        } catch (Exception ex) {
//                            Logger.getLogger(JcOaSyncUtil.class.getName()).log(Level.SEVERE, null, ex);
//                            continue;
//                        }
//                    }


                }
            }
        };
    }

    public File ReceiveFileThread(String serverIp, Integer serverPort){
        return new File("");
    }

    public static void main(String[] args) {

        ArrayList<File> list = FileTransferUtil.holdFiles;

        list.add(new File("~/Sandbox/tmp/aaa.txt"));
        list.add(new File("~/Sandbox/tmp/bbb.txt"));
        list.add(new File("~/Sandbox/tmp/ccc.txt"));
        list.add(new File("~/Sandbox/tmp/ddd.txt"));
        list.add(new File("~/Sandbox/tmp/eee.txt"));
        list.add(new File("~/Sandbox/tmp/fff.txt"));

        int listSize = list.size();

        for (int i=0; i<listSize; i++){
            System.out.println(FileTransferUtil.holdFiles.get(0).getPath());
            list.remove(0);
        }

    }
}
